import {defineComponent, h, PropType, ref, resolveComponent, watchEffect, watch} from 'vue';

import FxRender from '../render/index.ts';
import fxResolve from '../resolve/resolve.ts';
import {getValuesProxy, setValuesProxy, clearValuesProxy} from '../resolve/values.ts';
import {isArray} from '../resolve/utils.ts';

export default defineComponent({
  name: 'FxForm',
  inheritAttrs: false,
  props: {
    // 类名称
    class: {
      type: [String, Array, Object] as PropType<any>
    },
    // 字典数据
    dictData: {
      type: Object as PropType<any>
    },
    // 加载
    loading: {
      type: Boolean as PropType<boolean>
    },
    // 禁止输入
    disabled: {
      type: Boolean as PropType<boolean>
    },
    // 表单数据
    modelValue: {
      type: Object as PropType<any>
    },
    // 字段
    children: {
      type: [Object, Array] as PropType<any>
    },
    // 标签后缀
    labelSuffix: {
      type: Boolean as PropType<boolean>,
      default: false
    },
    // 初始化是否重置
    initReset: {
      type: Boolean as PropType<boolean>,
      default: true
    },
    // 清除时是否重置
    clearReset: {
      type: Boolean as PropType<boolean>,
      default: false
    }
  },
  emits: [
    'update:modelValue',
    'update:loading',
    'submit',
    'input'
  ],
  setup(props, context) {
    // defineExpose
    const {emit, expose} = context;
    const viewClass = ref();
    const key = ref(0);
    const info = ref({
      loading: false,
      disabled: false
    });
    const values = ref({});
    const children = ref([]);
    const columns = ref([]);
    const formRef = ref();

    const openLoad = () => {
      info.value.loading = true;
      emit('update:loading', info.value.loading);
    };
    const closeLoad = () => {
      info.value.loading = false;
      emit('update:loading', info.value.loading);
    };
    const setPropLoad = () => {
      info.value.loading = props.loading;
    };
    const initValues = () => {
      values.value = getValuesProxy(props.modelValue);
      setValuesProxy(values.value, columns.value);
      // 初始化数据时需要重新渲染表单，因为有可能绑定关系会失效
      if (props.initReset) {
        key.value = key.value + 1;
      }
    };
    const clearValues = () => {
      clearValuesProxy(columns.value, values.value);
      // 重置数据时需要重新渲染表单，如果使用undefined绑定关系肯定会失效,naiveui中需要使用null绑定关系
      if (props.clearReset) {
        key.value = key.value + 1;
      }
    };
    const validate = (done) => {
      if (!formRef.value) return;
      formRef.value.validate(done);
    };
    const resetFields = () => {
      if (!formRef.value) return;
      formRef.value.resetFields();
    };
    const scrollToField = (prop) => {
      if (!formRef.value) return;
      formRef.value.scrollToField(prop);
    };
    const clearValidate = () => {
      if (!formRef.value) return;
      formRef.value.clearValidate();
    };
    const validateField = (fields) => {
      if (!formRef.value) return;
      formRef.value.validateField(fields);
    };
    const onSubmit = (event: Event) => {
      // event.preventDefault();
      emit('submit', event, {
        data: props.modelValue,
        validate: validate,
        openLoad: openLoad,
        closeLoad: closeLoad
      });
    };
    const getObjectClass = (classes?: string | string[] | Pick<string, boolean>): object => {
      if (classes) {
        let classList;
        if (typeof classes === 'string') {
          classList = classes.split(' ');
        } else if (isArray(classes)) {
          classList = classes as string[];
        } else if (typeof classes === 'object') {
          return classes as object;
        }
        const classObject = {};
        if (classList && classList.length > 0) {
          for (let i = 0; i < classList.length; i++) {
            const name = classList[i];
            if (name) {
              classObject[name] = true;
            }
          }
        }
        return classObject;
      }
      return {};
    };

    watchEffect(() => {
      const classValue = getObjectClass(props.class);
      classValue['base-form'] = true;
      classValue['label-suffix'] = props.labelSuffix;
      classValue['fx-loading'] = info.value.loading;
      viewClass.value = classValue;
    });
    watchEffect(() => {
      const resolveResult = fxResolve.resolve(props.children, {size: context.attrs['size']});
      children.value = resolveResult.children;
      columns.value = resolveResult.bindKeys;
      console.log('render form >>> columns=', columns.value);
      console.log('render form >>> children=', children.value);
    });
    watchEffect(() => {
      // emit('update:modelValue', values.value);
      emit('input', props.modelValue);
    });
    watchEffect(() => {
      info.value.disabled = info.value.loading || props.disabled;
    });

    watch(() => props.loading, (newValue, oldValue) => {
      if (props.loading !== info.value.loading) {
        info.value.loading = props.loading;
      }
    });
    watch(() => [columns.value, props.modelValue], (newValue, oldValue) => {
      console.log('initValues->newValue=', newValue);
      initValues();
    }, {
      deep: false
    });

    initValues();
    setPropLoad();

    expose({
      initValues,
      clearValues,
      validate,
      resetFields,
      scrollToField,
      clearValidate,
      validateField
    });

    return () => {
      // noinspection TypeScriptValidateTypes
      return h(resolveComponent('NForm'), {
        key: key.value,
        ref: formRef,
        disabled: info.value.disabled,
        class: viewClass.value,
        model: values.value,
        ...context.attrs,
        onSubmit: onSubmit
      }, {
        default: () => {
          return h(FxRender, {
            children: children.value,
            data: values.value,
            info: info.value
          });
        }
      });
    };
  }
});